import { _decorator, Label, instantiate, Prefab, AudioClip, AudioSource, JsonAsset, Color, Component, find, Node, ProgressBar, resources, Sprite, SpriteFrame, Tween, tween, UITransform, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
import { colorHexArray } from './Color';
import { PixelItem } from './PixelItem';
import { GameManager } from './GameManager';

@ccclass('Monster')
export class Monster extends Component {
    @property({type: Prefab})
    damagePrefab: Prefab = null

    @property({type: Prefab})
    pixelItemPrefab: Prefab = null

    @property({type: Prefab})
    equipmentItemPrefab: Prefab = null

    @property({type: JsonAsset})
    equipmentJsonAsset: JsonAsset = null!

    @property({type: AudioClip})
    disappearAudio: AudioClip = null

    @property({type: AudioClip})
    hitMonsterAudio: AudioClip = null

    colorHex: string = null
    monsterInfo: object = null
    s1: SpriteFrame = null
    s2: SpriteFrame = null
    isDead: boolean = false
    moveTween: Tween<Node> = new Tween()
    equipmentJsonData: object = null

    gameManager: GameManager = null
    audioSource: AudioSource = null

    start() {
        this.initComponents()
        this.equipmentJsonData = this.equipmentJsonAsset.json
    }

    /** 
     * @zh
     * 初始化组件。
    */
    initComponents() {
        this.gameManager = find('Canvas').getComponent(GameManager)
        this.audioSource = find('Canvas').getComponent(AudioSource)
    }

    /** 
     * @zh
     * 初始化怪物信息。
    */
    setMonsterInfo(monsterInfo: object) {
        this.monsterInfo = monsterInfo
        this.setLifeProgressBar(monsterInfo['life'])
        this.setSpriteFrames(monsterInfo['pic1Path'], monsterInfo['pic2Path'])
        this.setRandomColor()
        this.setRandomStartPos()
    }

    /** 
     * @zh
     * 设置怪物图片。
    */
    setSpriteFrames(pic1Path: string, pic2Path: string) {
        let self = this
        resources.load(pic1Path, SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
            self.s1 = spriteFrame
            resources.load(pic2Path, SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
                self.s2 = spriteFrame
                self.node.children[1].getComponent(Sprite).spriteFrame = self.s1

                // 切换图片
                let callback = () => {
                    if (self.node.children[1].getComponent(Sprite).spriteFrame == self.s1) {
                        self.node.children[1].getComponent(Sprite).spriteFrame = self.s2
                    }
                    else {
                        self.node.children[1].getComponent(Sprite).spriteFrame = self.s1
                    }
                }
                self.schedule(callback, 0.3)
            })
        })
    }
    
    /** 
     * @zh
     * 设置随机颜色。
    */
    setRandomColor() {
        let num = Math.random()

        // 带有血药颜色的怪物应该多一些
        if (num>=0 && num <= 0.2) {
            this.colorHex = "cbdbfc"
        }
        else if (num > 0.2 && num <= 0.4) {
            this.colorHex = "ff0000"
        }
        else if (num > 0.4 && num <= 0.6) {
            this.colorHex = "493615"
        }
        else {
            let randomIndex = Math.floor(Math.random() * colorHexArray.length)
            this.colorHex = colorHexArray[randomIndex]
        }

        this.node.children[1].getComponent(Sprite).color = new Color().fromHEX(this.colorHex)
    }

    /** 
     * @zh
     * 设置随机开始位置。
    */
    setRandomStartPos() {
        let canvas = find('Canvas')
        let canvasWidth = canvas.getComponent(UITransform).width
        let canvasHeight = canvas.getComponent(UITransform).height
        let monsterWidth = this.node.getComponent(UITransform).width
        let monsterHeight = this.node.getComponent(UITransform).height

        let x = 0
        let y = 0
        let randomIndex = Math.floor(Math.random() * 4)
        // 在画布上面
        if (randomIndex == 0) {
            x = Math.random() * canvasWidth - canvasWidth / 2
            y = canvasHeight / 2 + monsterHeight
        }
        // 在画布下面
        else if (randomIndex == 1) {
            x = Math.random() * canvasWidth - canvasWidth / 2
            y = -canvasHeight / 2 - monsterHeight
        }
        // 在画布左边
        else if (randomIndex == 2) {
            x = -canvasWidth / 2 - monsterWidth
            y = Math.random() * canvasHeight - canvasHeight / 2
        }
        // 在画布右边
        else {
            x = canvasWidth / 2 + monsterWidth
            y = Math.random() * canvasHeight - canvasHeight / 2
        }

        this.node.setPosition(x, y, 0)
    }

    /** 
     * @zh
     * 根据血量设置进度条。
    */
    setLifeProgressBar(life: number) {
        let progressBarNode = this.node.children[0]
        progressBarNode.getComponent(UITransform).width = life
        progressBarNode.getComponent(ProgressBar).totalLength = life
        progressBarNode.children[0].setPosition(-progressBarNode.getComponent(UITransform).width/2, 0, 0)
    }

    /** 
     * @zh
     * 怪物移动。
    */
    move(speed: number) {
        // 不断朝主角移动
        // 如果怪物和主角的距离小于怪物身长一半，怪物停下
        let targetNodePos = find('Canvas/Player').position
        let distance = new Vec3(this.node.position).subtract(targetNodePos).length()
        if (distance < this.node.children[1].getComponent(UITransform).width/1.2) {
            return
        }

        let dir = new Vec3(this.node.position).subtract(targetNodePos).normalize()
        let pos = new Vec3(this.node.position).subtract3f(speed*dir.x, speed*dir.y, 0)
        this.node.setPosition(pos)

        // 设置方向
        if (targetNodePos.x >= this.node.position.x) {
            this.node.setScale(1, 1, 1)
            this.node.getChildByName('ProgressBar').setScale(0.5, 1, 1)       // 进度条不改变方向
        }
        else {
            this.node.setScale(-1, 1, 1)
            this.node.getChildByName('ProgressBar').setScale(-0.5, 1, 1)      // 进度条不改变方向
        }
    }

    /** 
     * @zh
     * 减少生命值。
    */
    reduceLife(damageValueFromPlayer: number) {
        if (damageValueFromPlayer - this.monsterInfo['defense'] <= 0) {
            //出现Miss
            this.showDamageValue(0)
        }
        else {
            let totalLength = this.node.children[0].getComponent(ProgressBar).totalLength
            let realDamage = damageValueFromPlayer - this.monsterInfo['defense']
            totalLength -= realDamage
            if (totalLength <= 0) {
                totalLength = 0
                this.showDamageValue(realDamage)
                this.die()
            }
            else {
                // 播放击中音频
                this.stepBack()
                this.showDamageValue(realDamage)
            }
            this.node.children[0].getComponent(ProgressBar).totalLength = totalLength
        }
    }

    /** 
     * @zh
     * 怪物死亡。
    */
    die() {
        this.isDead = true
        this.audioSource.playOneShot(this.disappearAudio)

        let targetNodePos = find('Canvas/Player').position
        let dir = new Vec3(this.node.position).subtract(targetNodePos).normalize()

        this.spawnEquipmentItem(dir)
        this.spawnPixelItem()

        // 弹飞
        let t1 = tween(this.node).by(0.2, {'eulerAngles': new Vec3(0, 0, 100)}).repeat(5)
        let t2 = tween(this.node).to(2, {'position': new Vec3(dir.x*2000, dir.y*2000)})
                                 .call(()=>{
                                    this.node.removeFromParent()
                                })
        tween(this.node).parallel(t1, t2).start()

        // 另一种死亡效果：透明度减少消失
        // let callback = () => {
        //     this.node.getComponent(UIOpacity).opacity -= 10
        //     if (this.node.getComponent(UIOpacity).opacity <= 0) {
        //         this.unscheduleAllCallbacks()
        //         this.node.removeFromParent()
        //     }
        // }
        // this.schedule(callback, 0.2)
    }
    
    /** 
     * @zh
     * 被攻击时后退。
    */
    stepBack() {
        this.audioSource.playOneShot(this.hitMonsterAudio, 3)
        let targetNodePos = find('Canvas/Player').position
        let dir = new Vec3(this.node.position).subtract(targetNodePos).normalize()
        tween(this.node).by(0.1, {'position': new Vec3(100*dir.x, 100*dir.y, 0)}, {'easing': 'sineInOut'}).start()
    }

    /** 
     * @zh
     * 显示受到的伤害。
    */
    showDamageValue(damageValue: number) {
        let damageNode = instantiate(this.damagePrefab)
        damageNode.getComponent(Label).color = new Color().fromHEX(this.colorHex)  // 怪物的Miss和受到的伤害值颜色为自身颜色

        if (damageValue <= 0) {
            damageNode.getComponent(Label).string = 'Miss'
        }
        else {
            damageNode.getComponent(Label).string = `-${damageValue}`
        }

        damageNode.setPosition(this.node.position)
        find('Canvas').addChild(damageNode)
        tween(damageNode).by(0.8, {'position': new Vec3(0, 60, 0)}, {'easing': 'sineOut'})
                   .call(()=>{damageNode.removeFromParent()})
                   .start()
    }

    /** 
     * @zh
     * 显示像素块。
    */
    spawnPixelItem() {
        let colorHex = this.node.children[1].getComponent(Sprite).color.toHEX()
        let pixelNum = Math.round(Math.random() * this.monsterInfo['pixelNum'] + this.monsterInfo['pixelNum'] / 10)
        let pixelItem = instantiate(this.pixelItemPrefab)
        pixelItem.getComponent(PixelItem).pixelNum = pixelNum
        pixelItem.getComponent(Sprite).color = new Color().fromHEX(colorHex)
        pixelItem.setPosition(this.node.position)
        pixelItem.getComponent(PixelItem).enabled = true
        pixelItem.setScale(1+0.1*pixelNum, 1+0.1*pixelNum, 1)
        find('Canvas').addChild(pixelItem)
    }

    /** 
     * @zh
     * 显示装备制作图。
    */
    spawnEquipmentItem(dir: Vec3) {
        // 一定概率没有出现制作图
        let randomNum = Math.random()
        if (randomNum <= 0.3) {
            return
        }

        // 大概率出现治疗药水
        let equipmentItem = instantiate(this.equipmentItemPrefab)
        if (randomNum > 0.7 && randomNum <= 0.9) {
            resources.load(this.equipmentJsonData['cure']['picPath'], SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
                equipmentItem.children[0].getComponent(Sprite).spriteFrame = spriteFrame
                equipmentItem.name = 'equipment-cure'
            })
        }
        else {
            let equipmentKeys = Object.keys(this.equipmentJsonData)
            let randomIndex = Math.floor(Math.random()*equipmentKeys.length)
            let randomEquipmentName = equipmentKeys[randomIndex]
            resources.load(this.equipmentJsonData[randomEquipmentName]['picPath'], SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
                equipmentItem.children[0].getComponent(Sprite).spriteFrame = spriteFrame
                equipmentItem.name = 'equipment-'+randomEquipmentName
            })
        }
        
        // 制作图不和pixelItem重合
        equipmentItem.setPosition(new Vec3(this.node.position).add3f(dir.x*equipmentItem.getComponent(UITransform).width, 0, 0))
        find('Canvas').addChild(equipmentItem)
    }

    update(deltaTime: number) {
        if (!this.isDead) {
            if (this.gameManager.isGamePaused) {  // 绘画时isGamePaused为true，此时让怪物移动速度减小（但不完全停止）
                this.move(this.monsterInfo['speed'] / 10)
            }
            else {
                this.move(this.monsterInfo['speed'])
            }
        }
    }
}


